/**************************************************************************** 
 * Meta，一个轻量级的静态分区Hypervisor 
 *
 * 版权(c) , 2022-
 *
 * 作者:
 *      Tupelo Shen <shenwanjiang2013@163.com>
 *
 * Meta是一个自由软件，你可以在遵循GNU GPLv2协议的条件下，重新修改并发布它。
 *
 ***************************************************************************/
#ifndef __VGIC_H__
#define __VGIC_H__

#include <meta.h>
#include <arch/gic.h>

struct vm;
struct vcpu;
struct gic_dscrp;

/**
 * TODO: optimize the vgic_int struct's size
 */
struct vgic_int {
    struct vcpu *owner;
#if (GIC_VERSION != GICV2)
    unsigned long route;
    union {
        vcpuid_t redist;
        unsigned long route;
    } phys;
#endif
    spinlock_t  lock;
    irqid_t     id;
    uint8_t     state;
    uint8_t     prio;
    uint8_t     cfg;
    uint8_t     lr;
#if (GIC_VERSION == GICV2)
    union {
        uint8_t targets;
        struct {
            uint8_t act;
            uint8_t pend;
        } sgi;
    };
#endif
    bool hw;
    bool in_lr;
    bool enabled;
};

struct vgicd {
    struct vgic_int *interrupts;
    spinlock_t lock;
    size_t int_num;
    uint32_t CTLR;
    uint32_t TYPER;
    uint32_t IIDR;
};

struct vgicr {
    spinlock_t lock;
    uint64_t TYPER;
    uint32_t CTLR;
    uint32_t IIDR;
};

/*
 * 保存虚拟中断控制器的列表寄存器
 * 保存虚拟中断控制器的私有中断（一般为16+16）
 */
struct vgic_priv {
#if (GIC_VERSION != GICV2)
    struct vgicr vgicr;
#endif
    irqid_t curr_lrs[GIC_NUM_LIST_REGS];
    struct vgic_int interrupts[GIC_CPU_PRIV];
};

void vgic_init(struct vm *vm, const struct gic_dscrp *gic_dscrp);
void vgic_cpu_init(struct vcpu *vcpu);
void vgic_set_hw(struct vm *vm, irqid_t id);
void vgic_inject(struct vgicd *vgicd, irqid_t id, vcpuid_t source);

/* VGIC INTERNALS */
/* VGIC对应的寄存器ID */
enum vgic_reg_handler_info_id {
    VGIC_ISENABLER_ID,
    VGIC_ISPENDR_ID,
    VGIC_ISACTIVER_ID,
    VGIC_ICENABLER_ID,
    VGIC_ICPENDR_ID,
    VGIC_ICACTIVER_ID,
    VGIC_ICFGR_ID,
    VGIC_IROUTER_ID,
    VGIC_IPRIORITYR_ID,
    VGIC_ITARGETSR_ID,
    VGIC_REG_HANDLER_ID_NUM
};

/* vgic寄存器处理信息（包括寄存器访问，读、写位域，更新硬件信息）
 * 用于模拟寄存器访问
 */
struct vgic_reg_handler_info {
    void (*reg_access)(struct emul_access *, struct vgic_reg_handler_info *,
                       bool gicr_accces, cpuid_t vgicr_id);
    size_t      alignment;
    size_t      regid;
    vaddr_t     regroup_base;
    size_t      field_width;
    uint64_t    (*read_field)  (struct vcpu *, struct vgic_int *);
    bool        (*update_field)(struct vcpu *, struct vgic_int *, uint64_t data);
    void        (*update_hw)   (struct vcpu *, struct vgic_int *);
};

/* vgic通用处理函数 */
bool        vgicd_emul_handler(struct emul_access *);
bool        vgic_check_reg_alignment(
                    struct emul_access *acc,
                    struct vgic_reg_handler_info *handlers
                    );
bool        vgic_add_lr         (struct vcpu *vcpu, struct vgic_int *interrupt);
bool        vgic_remove_lr      (struct vcpu *vcpu, struct vgic_int *interrupt);
bool        vgic_get_ownership  (struct vcpu *vcpu, struct vgic_int *interrupt);
void        vgic_yield_ownership(struct vcpu *vcpu, struct vgic_int *interrupt);
void        vgic_emul_generic_access(
                    struct emul_access *,
                    struct vgic_reg_handler_info *,
                    bool,
                    vcpuid_t
                    );
void        vgicd_emul_misc_access(
                    struct emul_access *acc,
                    struct vgic_reg_handler_info *handlers,
                    bool gicd_access,
                    cpuid_t vgicd_id
                    );
void        vgicd_emul_pidr_access(
                    struct emul_access *acc,
                    struct vgic_reg_handler_info *handlers,
                    bool gicd_access,
                    cpuid_t vgicd_id
                    );
void        vgic_send_sgi_msg(struct vcpu *vcpu, cpumap_t pcpu_mask, irqid_t int_id);
size_t      vgic_get_itln(const struct gic_dscrp *gic_dscrp);

/* vgic与架构版本有关的处理函数 */
bool        vgic_int_vcpu_is_target     (struct vcpu *vcpu, struct vgic_int *interrupt);
bool        vgic_int_has_other_target   (struct vcpu *vcpu, struct vgic_int *interrupt);
uint8_t     vgic_int_ptarget_mask       (struct vcpu *vcpu, struct vgic_int *interrupt);
void        vgic_inject_sgi             (struct vcpu *vcpu, struct vgic_int *interrupt,
                            vcpuid_t source);

#endif /* __VGIC_H__ */